Passed
Push — master ( 84fe03...41a79c )
by EMP
01:13
created

main.js ➔ reloadAccount   C

Complexity

Conditions 11

Size

Total Lines 72
Code Lines 47

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 47
dl 0
loc 72
rs 5.4
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like main.js ➔ reloadAccount often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"use strict";
2
3
sodium.ready.then(function() {
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
4
5
const ae = new AllEars(function(ok) {
1 ignored issue
show
Bug introduced by
The variable AllEars seems to be never declared. If this is a global, consider adding a /** global: AllEars */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
6
	if (ok) {
7
		const greeting = localStorage.greeting;
1 ignored issue
show
Bug introduced by
The variable localStorage seems to be never declared. If this is a global, consider adding a /** global: localStorage */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
8
		if (greeting) {
9
			document.getElementById("greeting").textContent = greeting;
10
			document.getElementById("txt_pg").value = greeting;
11
		}
12
13
		document.getElementById("txt_skey").style.background = "#466";
14
		document.getElementById("txt_skey").maxLength = "64";
15
	} else {
16
		console.log("Failed to load All-Ears");
17
	}
18
});
19
20
function TabState(cur, max, btnDele, btnUpdt) {
21
	this.cur = cur;
22
	this.max = max;
23
	this.btnDele = btnDele;
24
	this.btnUpdt = btnUpdt;
25
}
26
27
const tabs = [
28
	new TabState(0, 0, false, true), // Inbox
29
	new TabState(0, 0, false, true), // Outbx
30
	new TabState(0, 2, true, false), // Write
31
	new TabState(0, 2, false, false), // Notes
32
	new TabState(0, 3, false, true) // Tools
33
];
34
35
let showHeaders = false;
36
37
let tab = 0;
38
const TAB_INBOX = 0;
39
const TAB_DRBOX = 1;
40
const TAB_WRITE = 2;
41
const TAB_NOTES = 3;
42
const TAB_TOOLS = 4;
43
44
// Helper functions
45
function getCountryName(countryCode) {
46
	switch (countryCode) {
47
		case "DZ": return "Algeria";
48
		case "AO": return "Angola";
49
		case "BJ": return "Benin";
50
		case "BW": return "Botswana";
51
		case "BF": return "Burkina Faso";
52
		case "BI": return "Burundi";
53
		case "CV": return "Cabo Verde";
54
		case "CM": return "Cameroon";
55
		case "CF": return "Central African Republic";
56
		case "TD": return "Chad";
57
		case "KM": return "Comoros";
58
		case "CD": return "Congo";
59
		case "DJ": return "Djibouti";
60
		case "EG": return "Egypt";
61
		case "GQ": return "Equatorial Guinea";
62
		case "ER": return "Eritrea";
63
		case "SZ": return "Eswatini";
64
		case "ET": return "Ethiopia";
65
		case "GA": return "Gabon";
66
		case "GM": return "Gambia";
67
		case "GH": return "Ghana";
68
		case "GW": return "Guinea-Bissau";
69
		case "GN": return "Guinea";
70
		case "CI": return "Ivory Coast";
71
		case "KE": return "Kenya";
72
		case "LS": return "Lesotho";
73
		case "LR": return "Liberia";
74
		case "LY": return "Libya";
75
		case "MG": return "Madagascar";
76
		case "MW": return "Malawi";
77
		case "ML": return "Mali";
78
		case "MR": return "Mauritania";
79
		case "MU": return "Mauritius";
80
		case "YT": return "Mayotte";
81
		case "MA": return "Morocco";
82
		case "MZ": return "Mozambique";
83
		case "NA": return "Namibia";
84
		case "NE": return "Niger";
85
		case "NG": return "Nigeria";
86
		case "CG": return "Republic of the Congo";
87
		case "RW": return "Rwanda";
88
		case "RE": return "Réunion";
89
		case "SH": return "Saint Helena";
90
		case "SN": return "Senegal";
91
		case "SC": return "Seychelles";
92
		case "SL": return "Sierra Leone";
93
		case "SO": return "Somalia";
94
		case "ZA": return "South Africa";
95
		case "SS": return "South Sudan";
96
		case "SD": return "Sudan";
97
		case "ST": return "São Tomé and Príncipe";
98
		case "TZ": return "Tanzania";
99
		case "TG": return "Togo";
100
		case "TN": return "Tunisia";
101
		case "UG": return "Uganda";
102
		case "EH": return "Western Sahara";
103
		case "ZM": return "Zambia";
104
		case "ZW": return "Zimbabwe";
105
		case "AQ": return "Antarctica";
106
		case "BV": return "Bouvet Island";
107
		case "TF": return "French Southern Territories";
108
		case "HM": return "Heard Island and McDonald Islands";
109
		case "GS": return "South Georgia and the South Sandwich Islands";
110
		case "AF": return "Afghanistan";
111
		case "AM": return "Armenia";
112
		case "AZ": return "Azerbaijan";
113
		case "BH": return "Bahrain";
114
		case "BD": return "Bangladesh";
115
		case "BT": return "Bhutan";
116
		case "IO": return "British Indian Ocean Territory";
117
		case "BN": return "Brunei";
118
		case "KH": return "Cambodia";
119
		case "CN": return "China";
120
		case "CC": return "Cocos [Keeling] Islands";
121
		case "GE": return "Georgia";
122
		case "JO": return "Hashemite Kingdom of Jordan";
123
		case "HK": return "Hong Kong";
124
		case "IN": return "India";
125
		case "ID": return "Indonesia";
126
		case "IR": return "Iran";
127
		case "IQ": return "Iraq";
128
		case "IL": return "Israel";
129
		case "JP": return "Japan";
130
		case "KZ": return "Kazakhstan";
131
		case "KW": return "Kuwait";
132
		case "KG": return "Kyrgyzstan";
133
		case "LA": return "Laos";
134
		case "LB": return "Lebanon";
135
		case "MO": return "Macao";
136
		case "MY": return "Malaysia";
137
		case "MV": return "Maldives";
138
		case "MN": return "Mongolia";
139
		case "MM": return "Myanmar";
140
		case "NP": return "Nepal";
141
		case "KP": return "North Korea";
142
		case "OM": return "Oman";
143
		case "PK": return "Pakistan";
144
		case "PS": return "Palestine";
145
		case "PH": return "Philippines";
146
		case "QA": return "Qatar";
147
		case "SA": return "Saudi Arabia";
148
		case "SG": return "Singapore";
149
		case "KR": return "South Korea";
150
		case "LK": return "Sri Lanka";
151
		case "SY": return "Syria";
152
		case "TW": return "Taiwan";
153
		case "TJ": return "Tajikistan";
154
		case "TH": return "Thailand";
155
		case "TR": return "Turkey";
156
		case "TM": return "Turkmenistan";
157
		case "AE": return "United Arab Emirates";
158
		case "UZ": return "Uzbekistan";
159
		case "VN": return "Vietnam";
160
		case "YE": return "Yemen";
161
		case "AL": return "Albania";
162
		case "AD": return "Andorra";
163
		case "AT": return "Austria";
164
		case "BY": return "Belarus";
165
		case "BE": return "Belgium";
166
		case "BA": return "Bosnia and Herzegovina";
167
		case "BG": return "Bulgaria";
168
		case "HR": return "Croatia";
169
		case "CY": return "Cyprus";
170
		case "CZ": return "Czechia";
171
		case "DK": return "Denmark";
172
		case "EE": return "Estonia";
173
		case "FO": return "Faroe Islands";
174
		case "FI": return "Finland";
175
		case "FR": return "France";
176
		case "DE": return "Germany";
177
		case "GI": return "Gibraltar";
178
		case "GR": return "Greece";
179
		case "GG": return "Guernsey";
180
		case "HU": return "Hungary";
181
		case "IS": return "Iceland";
182
		case "IE": return "Ireland";
183
		case "IM": return "Isle of Man";
184
		case "IT": return "Italy";
185
		case "JE": return "Jersey";
186
		case "XK": return "Kosovo";
187
		case "LV": return "Latvia";
188
		case "LI": return "Liechtenstein";
189
		case "LU": return "Luxembourg";
190
		case "MT": return "Malta";
191
		case "MC": return "Monaco";
192
		case "ME": return "Montenegro";
193
		case "NL": return "Netherlands";
194
		case "MK": return "North Macedonia";
195
		case "NO": return "Norway";
196
		case "PL": return "Poland";
197
		case "PT": return "Portugal";
198
		case "LT": return "Republic of Lithuania";
199
		case "MD": return "Republic of Moldova";
200
		case "RO": return "Romania";
201
		case "RU": return "Russia";
202
		case "SM": return "San Marino";
203
		case "RS": return "Serbia";
204
		case "SK": return "Slovakia";
205
		case "SI": return "Slovenia";
206
		case "ES": return "Spain";
207
		case "SJ": return "Svalbard and Jan Mayen";
208
		case "SE": return "Sweden";
209
		case "CH": return "Switzerland";
210
		case "UA": return "Ukraine";
211
		case "GB": return "United Kingdom";
212
		case "VA": return "Vatican City";
213
		case "AX": return "Åland";
214
		case "AI": return "Anguilla";
215
		case "AG": return "Antigua and Barbuda";
216
		case "AW": return "Aruba";
217
		case "BS": return "Bahamas";
218
		case "BB": return "Barbados";
219
		case "BZ": return "Belize";
220
		case "BM": return "Bermuda";
221
		case "BQ": return "Bonaire, Sint Eustatius, and Saba";
222
		case "VG": return "British Virgin Islands";
223
		case "CA": return "Canada";
224
		case "KY": return "Cayman Islands";
225
		case "CR": return "Costa Rica";
226
		case "CU": return "Cuba";
227
		case "CW": return "Curaçao";
228
		case "DM": return "Dominica";
229
		case "DO": return "Dominican Republic";
230
		case "SV": return "El Salvador";
231
		case "GL": return "Greenland";
232
		case "GD": return "Grenada";
233
		case "GP": return "Guadeloupe";
234
		case "GT": return "Guatemala";
235
		case "HT": return "Haiti";
236
		case "HN": return "Honduras";
237
		case "JM": return "Jamaica";
238
		case "MQ": return "Martinique";
239
		case "MX": return "Mexico";
240
		case "MS": return "Montserrat";
241
		case "NI": return "Nicaragua";
242
		case "PA": return "Panama";
243
		case "PR": return "Puerto Rico";
244
		case "BL": return "Saint Barthélemy";
245
		case "LC": return "Saint Lucia";
246
		case "MF": return "Saint Martin";
247
		case "PM": return "Saint Pierre and Miquelon";
248
		case "VC": return "Saint Vincent and the Grenadines";
249
		case "SX": return "Sint Maarten";
250
		case "KN": return "St Kitts and Nevis";
251
		case "TT": return "Trinidad and Tobago";
252
		case "TC": return "Turks and Caicos Islands";
253
		case "VI": return "U.S. Virgin Islands";
254
		case "US": return "United States";
255
		case "AS": return "American Samoa";
256
		case "AU": return "Australia";
257
		case "CX": return "Christmas Island";
258
		case "CK": return "Cook Islands";
259
		case "TL": return "Democratic Republic of Timor-Leste";
260
		case "FM": return "Federated States of Micronesia";
261
		case "FJ": return "Fiji";
262
		case "PF": return "French Polynesia";
263
		case "GU": return "Guam";
264
		case "KI": return "Kiribati";
265
		case "MH": return "Marshall Islands";
266
		case "NR": return "Nauru";
267
		case "NC": return "New Caledonia";
268
		case "NZ": return "New Zealand";
269
		case "NU": return "Niue";
270
		case "NF": return "Norfolk Island";
271
		case "MP": return "Northern Mariana Islands";
272
		case "PW": return "Palau";
273
		case "PG": return "Papua New Guinea";
274
		case "PN": return "Pitcairn Islands";
275
		case "WS": return "Samoa";
276
		case "SB": return "Solomon Islands";
277
		case "TK": return "Tokelau";
278
		case "TO": return "Tonga";
279
		case "TV": return "Tuvalu";
280
		case "UM": return "U.S. Minor Outlying Islands";
281
		case "VU": return "Vanuatu";
282
		case "WF": return "Wallis and Futuna";
283
		case "AR": return "Argentina";
284
		case "BO": return "Bolivia";
285
		case "BR": return "Brazil";
286
		case "CL": return "Chile";
287
		case "CO": return "Colombia";
288
		case "EC": return "Ecuador";
289
		case "FK": return "Falkland Islands";
290
		case "GF": return "French Guiana";
291
		case "GY": return "Guyana";
292
		case "PY": return "Paraguay";
293
		case "PE": return "Peru";
294
		case "SR": return "Suriname";
295
		case "UY": return "Uruguay";
296
		case "VE": return "Venezuela";
297
	}
0 ignored issues
show
Comprehensibility introduced by
There is no default case in this switch, so nothing gets returned when all cases fail. You might want to consider adding a default or return undefined explicitly.
Loading history...
298
}
299
300
function getCountryFlag(countryCode) {
301
	return sodium.to_string(new Uint8Array([
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
302
		240, 159, 135, 166 + countryCode.codePointAt(0) - 65,
303
		240, 159, 135, 166 + countryCode.codePointAt(1) - 65
304
	]));
305
}
306
307
function getClockIcon(d) {
308
	const h24 = d.getUTCHours();
309
	let h12 = (h24 === 0 ? 12 : ((h24 > 12) ? h24 - 12 : h24));
310
311
	const m60 = (d.getUTCMinutes() * 60) + d.getUTCSeconds();
312
	let m30 = 0;
313
	if (m60 <= 900) { // <= 15: round down to this hour
314
		m30 = 0;
315
	} else if (m60 > 900 && m60 < 2700) { // 15..45: round to half-past this hour
316
		m30 = 12;
317
	} else { // >= 45: round up to next hour
318
		h12++;
319
		m30 = 0;
320
	}
321
322
	return "&#" + ((128335 + h12) + m30) + ";";
323
}
324
325
function getMsgId(num) {
326
	let i;
327
	if (ae.GetExtMsgHeaders(num).toLowerCase().slice(0, 11) === "message-id:") {
328
		i = 0;
329
	} else {
330
		i = ae.GetExtMsgHeaders(num).toLowerCase().indexOf("\nmessage-id:");
331
		if (i < 1) return "ERR";
332
		i++;
333
	}
334
335
	const x = ae.GetExtMsgHeaders(num).slice(i + 11).trim();
336
	if (x[0] !== "<") return "ERR2";
337
	return x.slice(1, x.indexOf(">"));
338
}
339
340
function clearDisplay() {
341
	let el = document.getElementById("midright").getElementsByTagName("img");
342
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("audio");
343
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("video");
344
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("embed");
345
	if (el.length !== 1) el = document.getElementById("midright").getElementsByTagName("iframe");
346
	if (el.length !== 1) return;
347
348
	URL.revokeObjectURL(el[0].src);
1 ignored issue
show
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
349
	el[0].remove();
350
}
351
352
function displayFile(num) {
353
	clearDisplay();
354
355
	document.getElementById("midright").scroll(0, 0);
356
	document.getElementById("midright").setAttribute("data-msgid", ae.GetUplMsgIdHex(num));
357
	document.getElementById("btn_reply").disabled = true;
358
	document.getElementById("btn_mdele").disabled = false;
359
	document.getElementById("midright").children[0].hidden = true;
360
	document.getElementById("midright").children[1].textContent = ae.GetUplMsgTitle(num);
361
362
	switch (ae.GetUplMsgType(num)) {
363
		case "text": {
364
			document.getElementById("midright").children[2].hidden = false;
365
			document.getElementById("midright").children[2].textContent = sodium.to_string(ae.GetUplMsgBody(num));
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
366
		break;}
367
368
		case "image": {
369
			document.getElementById("midright").children[2].hidden = true;
370
			const img = document.createElement("img");
371
			img.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
2 ignored issues
show
Bug introduced by
The variable Blob seems to be never declared. If this is a global, consider adding a /** global: Blob */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
Bug introduced by
The variable URL seems to be never declared. If this is a global, consider adding a /** global: URL */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
372
			document.getElementById("midright").appendChild(img);
373
374
			img.onclick = function() {
375
				if (!document.fullscreen)
376
					img.requestFullscreen();
377
				else
378
					document.exitFullscreen();
379
			};
380
		break;}
381
382
		case "audio": {
383
			document.getElementById("midright").children[2].hidden = true;
384
			const el = document.createElement("audio");
385
			el.controls = "controls";
386
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
387
			document.getElementById("midright").appendChild(el);
388
		break;}
389
390
		case "video": {
391
			document.getElementById("midright").children[2].hidden = true;
392
			const el = document.createElement("video");
393
			el.controls = "controls";
394
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer]));
395
			document.getElementById("midright").appendChild(el);
396
		break;}
397
398
		case "pdf": {
399
			document.getElementById("midright").children[2].hidden = true;
400
			const el = document.createElement("embed");
401
			el.type = "application/pdf";
402
			el.src = URL.createObjectURL(new Blob([ae.GetUplMsgBody(num).buffer], {type: "application/pdf"}));
403
			document.getElementById("midright").appendChild(el);
404
		break;}
405
406
		case "html": {
407
			document.getElementById("midright").children[2].hidden = true;
408
			const el = document.createElement("iframe");
409
			el.allow = "";
410
			el.sandbox = "";
411
			el.csp = "base-uri 'none'; child-src 'none'; connect-src 'none'; default-src 'none'; font-src 'none'; form-action 'none'; frame-ancestors 'none'; frame-src 'none'; img-src 'none'; manifest-src 'none'; media-src 'none'; object-src 'none'; script-src 'none'; style-src 'none'; worker-src 'none';";
412
			el.srcdoc = sodium.to_string(ae.GetUplMsgBody(num).buffer);
413
			document.getElementById("midright").appendChild(el);
414
		break;}
415
	}
416
}
417
418
function displayMsg(isInt, num) {
419
	clearDisplay();
420
421
	document.getElementById("btn_mdele").disabled = false;
422
	document.getElementById("midright").scroll(0, 0);
423
	document.getElementById("midright").setAttribute("data-msgid", isInt? ae.GetIntMsgIdHex(num) : ae.GetExtMsgIdHex(num));
424
425
	const ts = isInt? ae.GetIntMsgTime(num) : ae.GetExtMsgTime(num);
426
427
	document.getElementById("btn_reply").disabled = false;
428
	document.getElementById("btn_reply").onclick = function() {
429
		document.getElementById("write_recv").value = isInt? ae.GetIntMsgFrom(num) : ae.GetExtMsgReplyAddress(num);
430
		document.getElementById("write_subj").value = isInt? ae.GetIntMsgTitle(num) : ae.GetExtMsgTitle(num);
431
		if (!document.getElementById("write_subj").value.startsWith("Re:")) document.getElementById("write_subj").value = "Re: " + document.getElementById("write_subj").value;
432
		document.querySelector("#write2_pkey > input").value = isInt? ae.GetIntMsgFromPk(num) : "";
433
434
		document.getElementById("write_recv").readOnly = !isInt;
435
		document.getElementById("write_subj").readOnly = !isInt;
436
		document.getElementById("write_subj").setAttribute("data-replyid", isInt? "" : getMsgId(num));
437
438
		tabs[TAB_WRITE].cur = 0;
439
		document.getElementById("btn_write").disabled = false;
440
		document.getElementById("btn_write").click();
441
		document.getElementById("write_body").focus();
442
443
		for (const opt of document.getElementById("write_from").options) {
444
			if (opt.value === (isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num))) {
445
				opt.selected = true;
446
			}
447
		}
448
	};
449
450
	document.getElementById("midright").children[0].hidden = false;
451
	document.getElementById("midright").children[2].hidden = false;
452
453
	if (isInt) {
454
		document.getElementById("midright").children[1].textContent = ae.GetIntMsgTitle(num);
455
		document.getElementById("midright").children[2].textContent = ae.GetIntMsgBody(num);
456
	} else {
457
		document.getElementById("midright").children[2].innerHTML = "";
458
459
		const headers = document.createElement("p");
460
		headers.textContent = ae.GetExtMsgHeaders(num);
461
		headers.className = "mono";
462
		headers.hidden = !showHeaders;
463
		document.getElementById("midright").children[2].appendChild(headers);
464
465
		const body = document.createElement("p");
466
		body.textContent = ae.GetExtMsgBody(num);
467
		document.getElementById("midright").children[2].appendChild(body);
468
469
		document.getElementById("midright").children[1].textContent = ae.GetExtMsgTitle(num);
470
		document.getElementById("midright").children[1].onclick = function() {showHeaders = !showHeaders; headers.hidden = !showHeaders;};
471
		document.getElementById("midright").children[1].style.cursor = "pointer";
472
	}
473
474
	document.getElementById("readmsg_envto").textContent = isInt ? ae.GetIntMsgTo(num) : ae.GetExtMsgTo(num);
475
476
	const tzOs = new Date().getTimezoneOffset();
477
	const tz = ((tzOs < 0) ? "+" : "-") + Math.floor(tzOs / -60).toString().padStart(2, "0") + (tzOs % 60 * -1).toString().padStart(2, "0");
478
	const msgDate = new Date((ts * 1000) + (tzOs * -60000));
479
480
	document.getElementById("readmsg_date").children[0].innerHTML = getClockIcon(msgDate);
481
	document.getElementById("readmsg_date").children[1].textContent = msgDate.toISOString().slice(0, 19).replace("T", " ") + " " + tz;
482
483
	if (!isInt) {
484
		document.getElementById("readmsg_ip").hidden = false;
485
		document.getElementById("readmsg_country").hidden = false;
486
		document.getElementById("readmsg_tls").hidden = false;
487
		document.getElementById("readmsg_greet").hidden = false;
488
489
		const cc = ae.GetExtMsgCountry(num);
490
491
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetExtMsgIp(num);
492
		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
493
		document.getElementById("readmsg_tls").children[0].textContent = ae.GetExtMsgTLS(num);
494
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetExtMsgGreet(num);
495
		document.getElementById("readmsg_envfrom").textContent = ae.GetExtMsgFrom(num);
496
497
		let flagText = "";
498
		if (!ae.GetExtMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
499
		if (!ae.GetExtMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
500
		if (!ae.GetExtMsgFlagPExt(num)) flagText += "<abbr title=\"The sender did not use the Extended (ESMTP) protocol\">SMTP</abbr> ";
501
		if (!ae.GetExtMsgFlagQuit(num)) flagText += "<abbr title=\"The sender did not issue the required QUIT command\">QUIT</abbr> ";
502
		if (ae.GetExtMsgFlagRare(num)) flagText += "<abbr title=\"The sender issued unusual command(s)\">RARE</abbr> ";
503
		if (ae.GetExtMsgFlagFail(num)) flagText += "<abbr title=\"The sender issued invalid command(s)\">FAIL</abbr> ";
504
		if (ae.GetExtMsgFlagPErr(num)) flagText += "<abbr title=\"The sender violated the protocol\">PROT</abbr> ";
505
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
506
	} else {
507
		document.getElementById("readmsg_ip").hidden = true;
508
		document.getElementById("readmsg_country").hidden = true;
509
		document.getElementById("readmsg_greet").hidden = true;
510
511
		document.getElementById("readmsg_tls").hidden = false;
512
		document.getElementById("readmsg_tls").children[0].textContent = ae.GetIntMsgFromPk(num);
513
514
		let symbol = "<span title=\"Invalid level\">&#x26a0;</span>";
515
		if (ae.GetIntMsgFrom(num) === "system") {if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"System\">&#x1f162;</span>";} // S (System)
516
		else if (ae.GetIntMsgLevel(num) === 0) symbol = "<span title=\"Level 0 User\">&#x1f10c;</span>"; // 0
517
		else if (ae.GetIntMsgLevel(num) === 1) symbol = "<span title=\"Level 1 User\">&#x278a;</span>"; // 1
518
		else if (ae.GetIntMsgLevel(num) === 2) symbol = "<span title=\"Level 2 User\">&#x278b;</span>"; // 2
519
		else if (ae.GetIntMsgLevel(num) === 3) symbol = "<span title=\"Administrator\">&#x1f150;</span>"; // A (Admin)
520
		document.getElementById("readmsg_envfrom").innerHTML = symbol + " " + ae.GetIntMsgFrom(num);
521
522
		let flagText = "";
523
		if (!ae.GetIntMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
524
		if (!ae.GetIntMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
525
		if (ae.GetIntMsgFlagE2ee(num)) flagText += "<abbr title=\"End-to-end encrypted\">E2EE</abbr> ";
526
		document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
527
	}
528
}
529
530
// Interface
531
function addMsg(isInt, i) {
532
	const row = document.getElementById("tbl_inbox").insertRow(-1);
533
	row.setAttribute("data-msgid", isInt? ae.GetIntMsgIdHex(i) : ae.GetExtMsgIdHex(i));
534
535
	const cellTime = row.insertCell(-1);
536
	const cellSubj = row.insertCell(-1);
537
	const cellSnd1 = row.insertCell(-1);
538
	const cellSnd2 = row.insertCell(-1);
539
540
	const ts = isInt? ae.GetIntMsgTime(i) : ae.GetExtMsgTime(i);
541
	cellTime.setAttribute("data-ts", ts);
542
	cellTime.textContent = new Date((ts * 1000) + (new Date().getTimezoneOffset() * -60000)).toISOString().slice(0, 10);
543
544
	cellSubj.textContent = isInt? ae.GetIntMsgTitle(i) : ae.GetExtMsgTitle(i);
545
546
	if (isInt) {
547
		cellSnd1.textContent = ae.GetIntMsgFrom(i);
548
		cellSnd1.className = (ae.GetIntMsgFrom(i).length === 16) ? "mono" : "";
549
	} else {
550
		const from1 = ae.GetExtMsgFrom(i);
551
		const from2 = from1.substring(from1.indexOf("@") + 1);
552
		const cc = ae.GetExtMsgCountry(i);
553
554
		cellSnd1.textContent = from1.substring(0, from1.indexOf("@"));
555
556
		const flag = document.createElement("abbr");
557
		flag.textContent = getCountryFlag(cc);
558
		flag.title = getCountryName(cc);
559
		cellSnd2.appendChild(flag);
560
561
		const fromText = document.createElement("span");
562
		fromText.textContent = " " + from2;
563
		cellSnd2.appendChild(fromText);
564
	}
565
566
	row.onclick = function() {
567
		displayMsg(isInt, i);
568
	};
569
}
570
571
function getRowsPerPage() {
572
	const tbl = document.getElementById("tbl_inbox");
573
	tbl.innerHTML = "";
574
	const row = tbl.insertRow(-1);
575
	const cell = row.insertCell(-1);
576
	cell.textContent = "0";
577
578
	const rowsPerPage = Math.floor(getComputedStyle(document.getElementById("div_inbox")).height.replace("px", "") / getComputedStyle(document.querySelector("#tbl_inbox > tbody > tr:first-child")).height.replace("px", "")) - 1; // -1 allows space for 'load more'
579
	tbl.innerHTML = "";
580
	return rowsPerPage;
581
}
582
583
function addMessages() {
584
	const rowsPerPage = getRowsPerPage();
585
	let skipMsgs = rowsPerPage * tabs[TAB_INBOX].cur;
586
587
	const maxExt = ae.GetExtMsgCount();
588
	const maxInt = ae.GetIntMsgCount();
589
590
	tabs[TAB_INBOX].max = Math.floor((maxExt + maxInt - 1) / rowsPerPage);
591
592
	let numExt = 0;
593
	let numInt = 0;
594
	let numAdd = 0;
595
596
	while (numAdd < rowsPerPage) {
597
		const tsInt = (numInt < maxInt) ? ae.GetIntMsgTime(numInt) : -1;
598
		const tsExt = (numExt < maxExt) ? ae.GetExtMsgTime(numExt) : -1;
599
		if (tsInt === -1 && tsExt === -1) break;
600
601
		if (tsInt !== -1 && (tsExt === -1 || tsInt > tsExt)) {
602
			if (skipMsgs > 0) skipMsgs--; else {addMsg(true, numInt); numAdd++;}
603
			numInt++;
604
		} else if (tsExt !== -1) {
605
			if (skipMsgs > 0) skipMsgs--; else {addMsg(false, numExt); numAdd++;}
606
			numExt++;
607
		}
608
	}
609
610
	if (ae.GetReadyMsgBytes() < ae.GetTotalMsgBytes()) {
611
		const inbox = document.getElementById("tbl_inbox");
612
		const row = inbox.insertRow(-1);
613
		const cell = row.insertCell(-1);
614
		cell.textContent = "Load more (" + (ae.GetTotalMsgBytes() - ae.GetReadyMsgBytes()) / 1024 + " KiB left)";
615
616
		row.onclick = function() {
617
			this.onclick = "";
618
619
			ae.Message_Browse(false, false, function(successBrowse) {
620
				document.getElementById("tbl_inbox").style.opacity = 1;
621
622
				if (successBrowse) {
623
					addMessages();
624
					addUploads();
625
					addSent();
626
					if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
627
				}
628
			});
629
		};
630
	}
631
}
632
633
function addUploads() {
634
	const tbl = document.getElementById("tbd_uploads");
635
	tbl.innerHTML = "";
636
637
	for (let i = 0; i < ae.GetUplMsgCount(); i++) {
638
		const row = tbl.insertRow(-1);
639
		row.setAttribute("data-msgid", ae.GetUplMsgIdHex(i));
640
641
		let cell;
642
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetUplMsgTime(i) * 1000).toISOString().slice(0, 10);
643
644
		cell = row.insertCell(-1); cell.textContent = ae.GetUplMsgTitle(i);
645
		cell.onclick = function() {displayFile(this.parentElement.rowIndex - 1);};
646
647
		cell = row.insertCell(-1); cell.textContent = (ae.GetUplMsgBytes(i) / 1024).toFixed(1);
648
649
		cell = row.insertCell(-1);
650
		if (ae.GetUplMsgIdHex(i)) {
651
			cell.innerHTML = "<button data-msgid=\"" + ae.GetUplMsgIdHex(i) + "\" type=\"button\">X</button>";
652
653
			cell.children[0].onclick = function() {
654
				const tr = this.parentElement.parentElement;
655
				ae.Message_Delete(this.getAttribute("data-msgid"), function(success) {
656
					if (success) tr.remove();
657
				});
658
			};
659
		}
660
	}
661
}
662
663
function displayOutMsg(num) {
664
	clearDisplay();
665
	document.getElementById("midright").scroll(0, 0);
666
	document.getElementById("midright").setAttribute("data-msgid", ae.GetOutMsgIdHex(num));
667
	document.getElementById("btn_reply").disabled = true;
668
	document.getElementById("btn_mdele").disabled = false;
669
	document.getElementById("midright").children[0].hidden = false;
670
	document.getElementById("midright").children[2].hidden = false;
671
672
	document.getElementById("midright").children[1].textContent = ae.GetOutMsgSubj(num);
673
	document.getElementById("midright").children[2].textContent = ae.GetOutMsgBody(num);
674
675
	document.getElementById("readmsg_envto").textContent = ae.GetOutMsgTo(num);
676
	document.getElementById("readmsg_envfrom").textContent = ae.GetOutMsgFrom(num);
677
678
	const ts = ae.GetOutMsgTime(num);
679
	const tzOs = new Date().getTimezoneOffset();
680
	const tz = ((tzOs < 0) ? "+" : "-") + Math.floor(tzOs / -60).toString().padStart(2, "0") + (tzOs % 60 * -1).toString().padStart(2, "0");
681
	document.getElementById("readmsg_date").children[0].textContent = new Date((ts * 1000) + (tzOs * -60000)).toISOString().slice(0, 19).replace("T", " ") + " " + tz;
682
683
	const isInt = ae.GetOutMsgIsInt(num);
684
	document.getElementById("readmsg_ip").hidden      = isInt;
685
	document.getElementById("readmsg_country").hidden = isInt;
686
	document.getElementById("readmsg_tls").hidden     = isInt;
687
	document.getElementById("readmsg_greet").hidden   = isInt;
688
689
	if (!isInt) {
690
//		const cc = ae.GetExtMsgCountry(num);
691
692
		document.getElementById("readmsg_ip").children[0].textContent = ae.GetOutMsgIp(num);
693
//		document.getElementById("readmsg_country").textContent = getCountryFlag(cc) + " " + getCountryName(cc);
694
//		document.getElementById("readmsg_tls").children[0].textContent = ae.GetOutMsgTLS(num);
695
		document.getElementById("readmsg_greet").children[0].textContent = ae.GetOutMsgGreet(num);
696
	}
697
698
	let flagText = "";
699
	if (!ae.GetOutMsgFlagVPad(num)) flagText += "<abbr title=\"Invalid padding\">PAD</abbr> ";
700
	if (!ae.GetOutMsgFlagVSig(num)) flagText += "<abbr title=\"Invalid signature\">SIG</abbr> ";
701
	if (ae.GetOutMsgFlagE2ee(num)) flagText += "<abbr title=\"End-to-end encrypted\">E2EE</abbr> ";
702
	document.getElementById("readmsg_flags").children[0].innerHTML = flagText.trim();
703
}
704
705
function addSent() {
706
	const tbl = document.getElementById("tbl_drbox");
707
	tbl.innerHTML = "";
708
709
	for (let i = 0; i < ae.GetOutMsgCount(); i++) {
710
		const row = tbl.insertRow(-1);
711
		row.setAttribute("data-msgid", ae.GetOutMsgIdHex(i));
712
713
		let cell;
714
		cell = row.insertCell(-1); cell.textContent = new Date(ae.GetOutMsgTime(i) * 1000).toISOString().slice(0, 10);
715
		cell = row.insertCell(-1); cell.textContent = ae.GetOutMsgSubj(i);
716
		row.onclick = function() {displayOutMsg(i);};
717
	}
718
}
719
720
function updateAddressCounts() {
721
	document.getElementById("limit_normal").textContent = (ae.GetAddressCountNormal() + "/" + ae.GetLimitNormalA(ae.GetUserLevel())).padStart(ae.GetLimitNormalA(ae.GetUserLevel()) > 9 ? 5 : 1);
722
	document.getElementById("limit_shield").textContent = (ae.GetAddressCountShield() + "/" + ae.GetLimitShieldA(ae.GetUserLevel())).padStart(ae.GetLimitShieldA(ae.GetUserLevel()) > 9 ? 5 : 1);
723
	document.getElementById("limit_total").textContent = ((ae.GetAddressCountNormal() + ae.GetAddressCountShield()) + "/" + ae.GetAddrPerUser()).padStart(5);
724
}
725
726
function adjustLevel(pubkey, level, c) {
727
	const fs = document.getElementById("fs_accs");
728
	fs.disabled = true;
729
730
	ae.Account_Update(pubkey, level, function(success) {
731
		fs.disabled = false;
732
733
		if (success) {
734
			c[4].textContent = level;
735
			c[5].children[0].disabled = (level === 3);
736
			c[6].children[0].disabled = (level === 0);
737
		}
738
	});
739
}
740
741
function addAccountToTable(i) {
742
	const tblAccs = document.getElementById("tbd_accs");
743
	const row = tblAccs.insertRow(-1);
744
	let cell;
745
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserPkHex(i);
746
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSpace(i);
747
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserNAddr(i);
748
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserSAddr(i);
749
	cell = row.insertCell(-1); cell.textContent = ae.Admin_GetUserLevel(i);
750
751
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">+</button>";
752
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) + 1, c);};
753
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 3);
754
755
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">&minus;</button>";
756
	cell.children[0].onclick = function() {const c = this.parentElement.parentElement.cells; adjustLevel(c[0].textContent, parseInt(c[4].textContent) - 1, c);};
757
	cell.children[0].disabled = (ae.Admin_GetUserLevel(i) === 0);
758
759
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\">X</button>";
760
	cell.children[0].onclick = function() {
761
		const tr = this.parentElement.parentElement;
762
		ae.Account_Delete(tr.cells[0].textContent, function(success) {
763
			if (success) tr.remove();
764
		});
765
	};
766
}
767
768
function reloadAccount() {
769
	// Limits
770
	const tblLimits = document.getElementById("tbl_limits");
771
	if (ae.IsUserAdmin()) {
772
		for (let i = 0; i < 4; i++) {
773
			tblLimits.rows[i].cells[1].children[0].disabled = false;
774
			tblLimits.rows[i].cells[2].children[0].disabled = false;
775
			tblLimits.rows[i].cells[3].children[0].disabled = false;
776
777
			tblLimits.rows[i].cells[1].children[0].value = ae.GetLimitStorage(i) + 1;
778
			tblLimits.rows[i].cells[2].children[0].value = ae.GetLimitNormalA(i);
779
			tblLimits.rows[i].cells[3].children[0].value = ae.GetLimitShieldA(i);
780
		}
781
	} else {
782
		const lvl = ae.GetUserLevel();
783
		tblLimits.rows[lvl].cells[1].children[0].value = ae.GetLimitStorage(lvl) + 1;
784
		tblLimits.rows[lvl].cells[2].children[0].value = ae.GetLimitNormalA(lvl);
785
		tblLimits.rows[lvl].cells[3].children[0].value = ae.GetLimitShieldA(lvl);
786
	}
787
788
	// Accounts
789
	const tblAccs = document.getElementById("tbd_accs");
790
791
	// All: Our account
792
	const row = tblAccs.insertRow(-1);
793
	let cell;
794
	cell = row.insertCell(-1); cell.textContent = ae.GetUserPkHex();
795
	cell = row.insertCell(-1); cell.textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
796
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountNormal();
797
	cell = row.insertCell(-1); cell.textContent = ae.GetAddressCountShield();
798
	cell = row.insertCell(-1); cell.textContent = ae.GetUserLevel();
799
	cell = row.insertCell(-1); cell.innerHTML = "<button type=\"button\" autocomplete=\"off\" disabled=\"disabled\">+</button>";
800
801
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_downme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">&minus;</button>";
802
	cell.children[0].onclick = function() {
803
		const newLevel = parseInt(row.cells[4].textContent) - 1;
804
		ae.Account_Update(ae.GetUserPkHex(), newLevel, function(success) {
805
			if (success) row.cells[4].textContent = newLevel;
806
		});
807
	};
808
809
	cell = row.insertCell(-1); cell.innerHTML = "<button id=\"btn_killme\" type=\"button\" autocomplete=\"off\" disabled=\"disabled\">X</button>";
810
	cell.children[0].onclick = function() {
811
		ae.Account_Delete(ae.GetUserPkHex(), function(success) {
812
			if (success) row.remove();
813
		});
814
	};
815
816
	document.getElementById("txt_reg").disabled = !ae.IsUserAdmin();
817
	document.getElementById("btn_reg").disabled = !ae.IsUserAdmin();
818
819
	// Contacts
820
	for (let i = 0; i < ae.GetContactCount(); i++) {
821
		addContact(
822
			ae.GetContactMail(i),
823
			ae.GetContactName(i),
824
			ae.GetContactNote(i)
825
		);
826
	}
827
828
	// Addresses
829
	for (let i = 0; i < ae.GetAddressCount(); i++) {
830
		addAddress(i);
831
	}
832
833
	updateAddressCounts();
834
	addMessages();
835
	addUploads();
836
	addSent();
837
838
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
839
}
840
841
function deleteAddress(addr) {
842
	let btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
843
	for (let i = 0; i < btns.length; i++) btns[i].disabled = true;
844
845
	let addressToDelete = -1;
846
847
	for (let i = 0; i < ae.GetAddressCount(); i++) {
848
		if (addr === ae.GetAddress(i)) {
849
			addressToDelete = i;
850
			break;
851
		}
852
	}
853
854
	if (addressToDelete === -1) return;
855
856
	ae.Address_Delete(addressToDelete, function(success) {
857
		if (success) {
858
			document.getElementById("tbl_addrs").deleteRow(addressToDelete);
859
			document.getElementById("write_from").remove(addressToDelete);
860
			updateAddressCounts();
861
862
			if (ae.GetAddressCountNormal() < ae.GetLimitNormalA(ae.GetUserLevel())) document.getElementById("btn_address_create_normal").disabled = false;
863
			if (ae.GetAddressCountShield() < ae.GetLimitShieldA(ae.GetUserLevel())) document.getElementById("btn_address_create_shield").disabled = false;
864
865
			ae.Private_Update(function(success2) {
866
				if (!success2) console.log("Failed to update the Private field");
867
868
				btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
869
				for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
870
			});
871
		} else {
872
			console.log("Failed to delete address");
873
874
			btns = document.getElementById("tbl_addrs").getElementsByTagName("button");
875
			for (let i = 0; i < btns.length; i++) btns[i].disabled = false;
876
		}
877
	});
878
}
879
880 View Code Duplication
function shieldMix(addr) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
881
	let newAddr = "";
882
883
	for (let i = 0; i < 16; i++) {
884
		switch (addr.charAt(i)) {
885
			case '1':
886
				newAddr += "1iIlL".charAt(Math.floor(Math.random() * 5));
887
				break;
888
			case '0':
889
				newAddr += "0oO".charAt(Math.floor(Math.random() * 3));
890
				break;
891
			case 'w':
892
				newAddr += "VvWw".charAt(Math.floor(Math.random() * 4));
893
				break;
894
			default:
895
				newAddr += (Math.random() > 0.5) ? addr.charAt(i) : addr.charAt(i).toUpperCase();
896
		}
897
	}
898
899
	return newAddr;
900
}
901
902
function addAddress(num) {
903
	const addrTable = document.getElementById("tbl_addrs");
904
	const row = addrTable.insertRow(-1);
905
	const cellAddr = row.insertCell(-1);
906
	const cellChk1 = row.insertCell(-1);
907
	const cellChk2 = row.insertCell(-1);
908
	const cellBtnD = row.insertCell(-1);
909
910
	cellAddr.textContent = ae.GetAddress(num);
911
	cellAddr.onclick = function() {
912
		if (cellAddr.textContent.length === 16)
913
			navigator.clipboard.writeText(shieldMix(cellAddr.textContent) + "@" + ae.GetDomainEml());
1 ignored issue
show
Bug introduced by
The variable navigator seems to be never declared. If this is a global, consider adding a /** global: navigator */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
914
		else
915
			navigator.clipboard.writeText(cellAddr.textContent + "@" + ae.GetDomainEml());
916
	};
917
918
	cellChk1.innerHTML = ae.GetAddressAccExt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
919
	cellChk2.innerHTML = ae.GetAddressAccInt(num) ? "<input type=\"checkbox\" checked=\"checked\">" : "<input type=\"checkbox\">";
920
921
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
922
	cellBtnD.onclick = function() {deleteAddress(cellAddr.textContent);};
923
924
	const opt = document.createElement("option");
925
	opt.value = cellAddr.textContent;
926
	opt.textContent = cellAddr.textContent + "@" + ae.GetDomainEml();
927
	document.getElementById("write_from").appendChild(opt);
928
}
929
930
document.getElementById("btn_dele").onclick = function() {
931
	this.blur();
932
933
	if (tab === TAB_WRITE) {
934
		tabs[tab].cur = 0;
935
		updateTab();
936
937
		document.getElementById("write_recv").value = "";
938
		document.getElementById("write_subj").value = "";
939
		document.getElementById("write_body").value = "";
940
941
		document.getElementById("write_recv").readOnly = false;
942
		document.getElementById("write_subj").readOnly = false;
943
		document.getElementById("write_subj").setAttribute("data-replyid", "");
944
945
		document.getElementById("write_recv").focus();
946
	}
947
};
948
949
document.getElementById("btn_updt").onclick = function() {
950
	const btn = this;
951
	btn.disabled = true;
952
	btn.blur();
953
954
	if (tab === TAB_INBOX) {
955
		document.getElementById("tbl_inbox").style.opacity = 0.5;
956
957
		ae.Message_Browse(true, false, function(successBrowse) {
958
			document.getElementById("tbl_inbox").style.opacity = 1;
959
960
			if (successBrowse) {
961
				addMessages();
962
				addUploads();
963
				btn.disabled = false;
964
			} else {
965
				console.log("Failed to refresh");
966
				btn.disabled = false;
967
			}
968
		});
969
	}
970
};
971
972
document.getElementById("btn_mdele").onclick = function() {
973
	const btn = this;
974
	btn.blur();
975
	btn.disabled = true;
976
977
	const delId = document.getElementById("midright").getAttribute("data-msgid");
978
	if (!delId) return;
979
980
	ae.Message_Delete(delId, function(success) {
981
		if (success) {
982
			["tbl_inbox", "tbl_drbox", "tbd_uploads"].forEach(function(tbl_name) {
983
				const tbl = document.getElementById(tbl_name);
984
				for (let i = 0; i < tbl.rows.length; i++) {if (tbl.rows[i].getAttribute("data-msgid") === delId) tbl.deleteRow(i);}
985
			});
986
987
			addMessages();
988
			addUploads();
989
			addSent();
990
		} else btn.disabled = false;
991
	});
992
};
993
994
function addContact(mail, name, note) {
995
	const tbl = document.getElementById("tbl_ctact");
996
	const row = tbl.insertRow(-1);
997
	const cellMail = row.insertCell(-1);
998
	const cellName = row.insertCell(-1);
999
	const cellNote = row.insertCell(-1);
1000
	const cellBtnD = row.insertCell(-1);
1001
1002
	cellMail.textContent = mail;
1003
	cellName.textContent = name;
1004
	cellNote.textContent = note;
1005
	cellBtnD.innerHTML = "<button type=\"button\">X</button>";
1006
1007
	cellMail.contentEditable = true;
1008
	cellName.contentEditable = true;
1009
	cellNote.contentEditable = true;
1010
1011
	cellBtnD.onclick = function() {row.remove();};
1012
}
1013
1014
document.getElementById("btn_newcontact").onclick = function() {
1015
	addContact("", "", "");
1016
};
1017
1018
document.getElementById("btn_savecontacts").onclick = function() {
1019
	while (ae.GetContactCount() > 0) {
1020
		ae.DeleteContact(0);
1021
	}
1022
1023
	for (const row of document.getElementById("tbl_ctact").rows) {
1024
		ae.AddContact(row.cells[0].textContent, row.cells[1].textContent, row.cells[2].textContent);
1025
	}
1026
1027
	const btn = this;
1028
	btn.disabled = true;
1029
1030
	ae.Private_Update(function(success) {
1031
		btn.disabled = false;
1032
1033
		if (!success) {
1034
			console.log("Failed contacts update");
1035
		}
1036
	});
1037
};
1038
1039
function writeVerify() {
1040
	document.getElementById("div_write_1").hidden = true;
1041
	document.getElementById("div_write_2").hidden = false;
1042
1043
	document.getElementById("write2_recv").textContent = document.getElementById("write_recv").value;
1044
	document.getElementById("write2_subj").textContent = document.getElementById("write_subj").value;
1045
	document.getElementById("write2_rply").textContent = document.getElementById("write_subj").getAttribute("data-replyid");
1046
	document.getElementById("write2_body").textContent = document.getElementById("write_body").value;
1047
1048
	if (document.getElementById("write_recv").value.indexOf("@") >= 0) {
1049
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value + "@" + ae.GetDomainEml();
1050
		document.getElementById("write2_pkey").hidden = true;
1051
	} else {
1052
		document.getElementById("write2_from").textContent = document.getElementById("write_from").value;
1053
		document.getElementById("write2_pkey").hidden = false;
1054
	}
1055
}
1056
1057
function updateTab() {
1058
	switch (tab) {
1059
		case TAB_INBOX:
1060
			addMessages();
1061
		break;
1062
1063
		case TAB_DRBOX:
1064
			addSent();
1065
		break;
1066
1067
		case TAB_WRITE:
1068
			switch (tabs[tab].cur) {
1069
				case 0: // Write
1070
					document.getElementById("div_write_1").hidden = false;
1071
					document.getElementById("div_write_2").hidden = true;
1072
					document.getElementById("write_body").focus();
1073
				break;
1074
1075
				case 1: // Verify
1076
					writeVerify();
1077
				break;
1078
1079
				case 2: // Send
1080
					ae.Message_Create(
1081
						document.getElementById("write_subj").value,
1082
						document.getElementById("write_body").value,
1083
						document.getElementById("write_from").value,
1084
						document.getElementById("write_recv").value,
1085
						document.getElementById("write_subj").getAttribute("data-replyid"),
1086
						(document.getElementById("write2_recv").textContent.indexOf("@") > 0) ? null : sodium.from_base64(document.querySelector("#write2_pkey > input").value, sodium.base64_variants.ORIGINAL_NO_PADDING),
1 ignored issue
show
Bug introduced by
The variable sodium seems to be never declared. If this is a global, consider adding a /** global: sodium */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1087
						function(success) {
1088
							if (success) {
1089
								console.log("Sent ok");
1090
							} else {
1091
								console.log("Failed sending");
1092
							}
1093
						}
1094
					);
1095
				break;
1096
			}
1097
		break;
1098
1099
		case TAB_NOTES:
1100
			for (let i = 0; i <= tabs[tab].max; i++) {
1101
				document.getElementById("div_notes").children[i].hidden = (i !== tabs[tab].cur);
1102
			}
1103
		break;
1104
1105
		case TAB_TOOLS:
1106
			for (let i = 0; i <= tabs[tab].max; i++) {
1107
				document.getElementById("div_tools").children[i].hidden = (i !== tabs[tab].cur);
1108
			}
1109
		break;
1110
	}
1111
1112
	document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
1113
	document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
1114
}
1115
1116
document.getElementById("btn_left").onclick = function() {
1117
	tabs[tab].cur--;
1118
	if (tabs[tab].cur === 0) this.disabled = true;
1119
	if (tabs[tab].cur < tabs[tab].max) document.getElementById("btn_rght").disabled = false;
1120
	updateTab();
1121
	this.blur();
1122
};
1123
1124
document.getElementById("btn_rght").onclick = function() {
1125
	tabs[tab].cur++;
1126
	if (tabs[tab].cur === tabs[tab].max) this.disabled = true;
1127
	document.getElementById("btn_left").disabled = false;
1128
	updateTab();
1129
	this.blur();
1130
};
1131
1132
const buttons = document.querySelector("#main1 > .top").getElementsByTagName("button");
1133
for (let i = 0; i < buttons.length; i++) {
1134
	buttons[i].onclick = function() {
1135
		tab = i;
1136
1137
		for (let j = 0; j < buttons.length; j++) {
1138
			document.querySelector("#main1 > .mid").children[j].hidden = (tab !== j);
1139
			buttons[j].disabled = (tab === j);
1140
		}
1141
1142
		document.getElementById("btn_left").disabled = (tabs[tab].cur === 0);
0 ignored issues
show
Bug introduced by
The variable tab is changed as part of the for loop for example by i on line 1135. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
1143
		document.getElementById("btn_rght").disabled = (tabs[tab].cur === tabs[tab].max);
1144
		document.getElementById("btn_dele").disabled = !tabs[tab].btnDele;
1145
		document.getElementById("btn_updt").disabled = !tabs[tab].btnUpdt;
1146
1147
		updateTab();
1148
	};
1149
}
1150
1151
function addressCreate(addr) {
1152
	const btnN = document.getElementById("btn_address_create_normal");
1153
	const btnS = document.getElementById("btn_address_create_shield");
1154
	btnN.disabled = true;
1155
	btnS.disabled = true;
1156
1157
	ae.Address_Create(addr, function(success1) {
1158
		if (success1) {
1159
			ae.Private_Update(function(success2) {
1160
				addAddress(ae.GetAddressCount() - 1);
1161
				if (addr !== "SHIELD") document.getElementById("txt_address_create_normal").value = "";
1162
				updateAddressCounts();
1163
1164
				if (!success2) console.log("Failed to update the Private field");
1165
1166
				if (ae.GetAddressCountNormal() < ae.GetLimitNormalA(ae.GetUserLevel())) btnN.disabled = false;
1167
				if (ae.GetAddressCountShield() < ae.GetLimitShieldA(ae.GetUserLevel())) btnS.disabled = false;
1168
			});
1169
		} else {
1170
			console.log("Failed to add address");
1171
1172
			if (ae.GetAddressCountNormal() < ae.GetLimitNormalA(ae.GetUserLevel())) btnN.disabled = false;
1173
			if (ae.GetAddressCountShield() < ae.GetLimitShieldA(ae.GetUserLevel())) btnS.disabled = false;
1174
		}
1175
	});
1176
}
1177
1178
document.getElementById("btn_address_create_normal").onclick = function() {
1179
	if (ae.GetAddressCountNormal() >= ae.GetLimitNormalA(ae.GetUserLevel())) return;
1180
1181
	const txtNewAddr = document.getElementById("txt_address_create_normal");
1182
	if (!txtNewAddr.reportValidity()) return;
1183
1184
	addressCreate(txtNewAddr.value);
1185
};
1186
1187
document.getElementById("btn_address_create_shield").onclick = function() {
1188
	if (ae.GetAddressCountShield() >= ae.GetLimitShieldA(ae.GetUserLevel())) return;
1189
1190
	addressCreate("SHIELD");
1191
};
1192
1193
document.getElementById("btn_address_update").onclick = function() {
1194
	const btn = this;
1195
	btn.disabled = true;
1196
1197
	const rows = document.getElementById("tbl_addrs").rows;
1198
1199
	for (let i = 0; i < rows.length; i++) {
1200
		ae.SetAddressAccExt(i, rows[i].getElementsByTagName("input")[0].checked);
1201
		ae.SetAddressAccInt(i, rows[i].getElementsByTagName("input")[1].checked);
1202
	}
1203
1204
	ae.Address_Update(function(success) {
1205
		if (!success) console.log("Address/Update failed");
1206
		btn.disabled = false;
1207
	});
1208
};
1209
1210
document.getElementById("btn_reg").onclick = function() {
1211
	const btn = document.getElementById("btn_reg");
1212
	const txt = document.getElementById("txt_reg");
1213
	if (!txt.reportValidity()) return;
1214
	btn.disabled = true;
1215
1216
	ae.Account_Create(txt.value, function(success) {
1217
		if (success) {
1218
			addAccountToTable(ae.Admin_GetUserCount() - 1);
1219
			txt.value = "";
1220
		}
1221
1222
		btn.disabled = false;
1223
	});
1224
};
1225
1226
document.getElementById("chk_downme").onclick = function() {document.getElementById("btn_downme").disabled = !this.checked;};
1227
document.getElementById("chk_killme").onclick = function() {document.getElementById("btn_killme").disabled = !this.checked;};
1228
1229
document.getElementById("btn_notepad_saveupl").onclick = function() {
1230
	const np = document.getElementById("txt_notepad");
1231
	np.disabled = true;
1232
1233
	let fname = prompt("Save as...", "Untitled");
0 ignored issues
show
Debugging Code Best Practice introduced by
The prompt UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
1234
	if (!fname.endsWith(".txt")) fname += ".txt";
1235
1236
	ae.Message_Upload(fname, np.value, function(success) {
1237
		if (success) {
1238
			np.value = "";
1239
			addUploads();
1240
			document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
1241
		}
1242
1243
		console.log("Failed to add text");
1244
		np.disabled = false;
1245
	});
1246
};
1247
1248
document.getElementById("btn_upload").onclick = function() {
1249
	const btn = this;
1250
	const fileSelector = document.createElement("input");
1251
	fileSelector.type = "file";
1252
	fileSelector.click();
1253
1254
	fileSelector.onchange = function() {
1255
		btn.disabled = true;
1256
1257
		const reader = new FileReader();
1 ignored issue
show
Bug introduced by
The variable FileReader seems to be never declared. If this is a global, consider adding a /** global: FileReader */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1258
		reader.onload = function() {
1259
			ae.Message_Upload(fileSelector.files[0].name, new Uint8Array(reader.result), function(success) {
1260
				if (success) {
1261
					addUploads();
1262
					document.getElementById("tbd_accs").children[0].children[1].textContent = Math.round(ae.GetTotalMsgBytes() / 1024 / 1024);
1263
				} else {
1264
					console.log("Failed upload");
1265
				}
1266
1267
				btn.disabled = false;
1268
			});
1269
		};
1270
1271
		reader.readAsArrayBuffer(fileSelector.files[0]);
1272
	};
1273
};
1274
1275
document.getElementById("btn_pg").onclick = function() {
1276
	localStorage.greeting = document.getElementById("txt_pg").value;
1 ignored issue
show
Bug introduced by
The variable localStorage seems to be never declared. If this is a global, consider adding a /** global: localStorage */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
1277
};
1278
1279
document.getElementById("txt_skey").onkeyup = function(event) {
1280
	if (event.key === "Enter") {
1281
		event.preventDefault();
1282
		document.getElementById("btn_enter").click();
1283
	}
1284
};
1285
1286
document.getElementById("btn_enter").onclick = function() {
1287
	const txtSkey = document.getElementById("txt_skey");
1288
	if (!txtSkey.reportValidity()) return;
1289
1290
	const btn = this;
1291
	btn.disabled = true;
1292
	document.getElementById("txt_skey").style.background = "#233";
1293
1294
	ae.SetKeys(txtSkey.value, function(successSetKeys) {
1295
		if (successSetKeys) {
1296
			ae.Message_Browse(false, true, function(successBrowse) {
1297
				if (successBrowse) {
1298
					txtSkey.value = "";
1299
					document.getElementById("div_begin").hidden = true;
1300
					document.getElementById("div_main").style.display = "grid";
1301
					reloadAccount();
1302
1303
					if (ae.IsUserAdmin()) {
1304
						ae.Account_Browse(function(successAcc) {
1305
							if (successAcc) {for (let i = 0; i < ae.Admin_GetUserCount(); i++) {addAccountToTable(i);}}
1306
							else console.log("Failed to Account_Browse");
1307
						});
1308
					}
1309
				} else {
1310
					console.log("Failed to enter");
1311
					btn.disabled = false;
1312
					document.getElementById("txt_skey").style.background = "#466";
1313
					txtSkey.focus();
1314
				}
1315
			});
1316
		} else {
1317
			console.log("Invalid format for key");
1318
			btn.disabled = false;
1319
			document.getElementById("txt_skey").style.background = "#466";
1320
			txtSkey.focus();
1321
		}
1322
	});
1323
};
1324
1325
});
1326